package com.powerfl.frm.taf{
	
	import flash.display.*;
	import flash.events.*;
	import flash.media.*;
	import flash.system.*;
	import flash.text.*;
	import flash.utils.*;
	
	final internal class TAFembed{
		
		private var _end:Function;
		
		private var _embed:Object;

		public function TAFembed(){}
		
		internal function init( $target:*, $end:Function ):void{
			var key:*, name:String, loadList:Array, result:Object, target:Class, instance:*;
			
			_end = $end;
			
			_embed = {
				Class:{},
				ApplicationDomain:{},
				BitmapData:{},
				Sprite:{},
				Sound:{},
				ByteArray:{},
				pbj:{},
				res:{}
			};
			
			loadList = [];
			
			for each( key in describeType( $target ).variable.( @type == 'Class' ) ){
				name = key.@name[0];
				target = $target[name];
				instance = new target;
				
				switch( name.substr( 0, 3 ) ){
				case'CLS':case'IMG':case'MP3':
					loadList.push( [name.substr( 0, 3 ), name.substr( 3 ), instance] );
					break;
				default:
					if( instance is Bitmap ){
						_embed.BitmapData[name] = instance.bitmapData;
						_embed.key[name] = 'BitmapData';
					}else if( instance is ByteArray ){
						_embed.ByteArray[name] = target;
						_embed.key[name] = 'ByteArray';
					}else if( instance is Sprite ){
						_embed.Sprite[name] = target;
						_embed.key[name] = 'Sprite';
					}else if( instance is Font ){
						Font.registerFont( target );
						_embed.key[name] = 'Font';
					}else if( instance is Sound ){
						_embed.Sound[name] = target;
						_embed.key[name] = 'Sound';
					}else{
						_embed.Class[name] = target;
						_embed.key[name] = 'Class';
					}
					
					break;
				}
			}
			
			if( loadList.length ){
				loadResource( loadList );
			}else{
				_end();
			}
		}
		private function loadResource( $list:Array, $cursor:int = 0 ):void{
			var loader:Loader, context:LoaderContext, key:*, temp:Array;
			
			switch( $list[$cursor][0] ){
			case'CLS':case'IMG':
				loader = new Loader;
				context = new LoaderContext;
				context.applicationDomain = new ApplicationDomain;
				if( 'allowCodeImport' in context ){
					context.allowCodeImport = true;
				}else if( 'allowLoadBytesCodeExecution' in context ){
					context.allowLoadBytesCodeExecution = true;
				}
				
				if( Security.sandboxType === Security.REMOTE ){
					context.securityDomain = SecurityDomain.currentDomain;
					context.checkPolicyFile = true;
				}
				loader.loaderInfo.addEventListener( Event.COMPLETE, function( $e:Event ):void{
					$e.target.removeEventListener( $e.type, arguments.callee );
					_embed.ApplicationDomain[$list[$cursor][1]] = $e.target.applicationDomain;
					if( ++$cursor === $list.length ){
						_end();
					}else{
						arguments.callee( $list, $cursor );
					}
				} );
				loader.loadBytes( $list[$cursor][2], context );
				break;
			case'MP3':
				_end();
			}
		}
		public function getKey( $key:String, ...$param ):*{
			switch( _embed.key[$key] ){
			case'BitmapData': return bitmapData( $key );
			case'ByteArray': return byteArray( $key );
			case'Sprite': return sprite( $key );
			case'Sound': return sound( $key );
			case'Class': return instance( $key, '', $param );
			case'Font':default: return null;
			}
		}
		public function bitmapData( $key:String ):BitmapData{
			if( _embed.BitmapData[$key] ){
				return ( _embed.BitmapData[$key] as BitmapData ).clone();
			}else{
				return null;
			}
		}
		public function sprite( $key:String ):Sprite{
			return new _embed.Sprite[$key] as Sprite;
		}
		public function sound( $key:String ):Sound{
			if( _embed.Sound[$key] ){
				return new _embed.Sound[$key] as Sound;
			}else{
				return null;
			}
		}
		public function shader( $key:String ):Shader{
			return new Shader( byteArray( $key ) );
		}
		public function byteArray( $key:String ):ByteArray{
			if( _embed.ByteArray[$key] ){
				return new _embed.ByteArray[$key];
			}else{
				return null;
			}
		}
		public function className( $className:String, $applicationDomain:String = '' ):Class{
			if( $applicationDomain ){
				return _embed.ApplicationDomain[$applicationDomain][$className] as Class;
			}else{
				return _embed['Class'][$className] as Class;
			}
		}
		public function instance( $className:String, $applicationDomain:String = '', $param:Array = null ):*{
			var cls:Class;
			cls = className( $className, $applicationDomain );
			if( $param ){
				switch( $param.length ){
				case 1: return new cls( $param[0] );
				case 2: return new cls( $param[0], $param[1] );
				case 3: return new cls( $param[0], $param[1], $param[2] );
				case 4: return new cls( $param[0], $param[1], $param[2], $param[3] );
				case 5: return new cls( $param[0], $param[1], $param[2], $param[3], $param[4] );
				case 6: return new cls( $param[0], $param[1], $param[2], $param[3], $param[4], $param[5] );
				case 7: return new cls( $param[0], $param[1], $param[2], $param[3], $param[4], $param[5], $param[6] );
				case 8: return new cls( $param[0], $param[1], $param[2], $param[3], $param[4], $param[5], $param[6], $param[7] );
				case 9: return new cls( $param[0], $param[1], $param[2], $param[3], $param[4], $param[5], $param[6], $param[7], $param[8] );
				case 10: return new cls( $param[0], $param[1], $param[2], $param[3], $param[4], $param[5], $param[6], $param[7], $param[8], $param[9] );
				case 0:default: return new cls;
				}
			}else{
				return new cls;
			}
		}
		
		public function setBitmapData( $key:String, $data:BitmapData ):void{
			if( _embed.BitmapData[$key] ){
				_embed.BitmapData[$key].dispose();
			}
			_embed.BitmapData[$key] = $data;
		}
	}
}